package c.c0der.jsgl;

import android.app.Activity;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;

import com.didi.virtualapk.PluginManager;
import com.didi.virtualapk.internal.LoadedPlugin;
import com.example.base.Entry;

import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import c.c0der.jsgl.jso.JSOAndroid;
import c.c0der.jsgl.jso.JSObjectGL20;

public class MainActivity extends Activity {
    private GLSurfaceView glSurfaceView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        glSurfaceView = new MyGLSurface(this, new GLSurfaceView.Renderer() {
//            @Override
//            public void onSurfaceCreated(GL10 gl, EGLConfig config) {
////                if (gl instanceof GLES20)
////                GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
//            }
//
//            @Override
//            public void onSurfaceChanged(GL10 gl, int width, int height) {
//                GLES20.glViewport(0, 0, width, height);
//                runJS();
////                runNative2();
//            }
//
//            @Override
//            public void onDrawFrame(GL10 gl) {
//
//            }
//        });
//        setContentView(glSurfaceView);

//        FrameLayout root = new FrameLayout(this);
        String pluginPath = new File(Environment.getExternalStorageDirectory(), "plugin.apk").getAbsolutePath();
        PackageManager pm = getPackageManager();
        PackageInfo packageInfo = pm.getPackageArchiveInfo(pluginPath, 0);
        File pluginFile = new File(pluginPath);
        try {
            PluginManager.getInstance(this).loadPlugin(pluginFile);
            LoadedPlugin plugin = PluginManager.getInstance(this).getLoadedPlugin(packageInfo.packageName);
            Class clazz = plugin.getClassLoader().loadClass(packageInfo.packageName + ".CCEntry");
            Entry entry = (Entry) clazz.newInstance();

            InputStream source = plugin.getResources().openRawResource(entry.sourceID());
            runJS(source);
            View layout = LayoutInflater.from(plugin.getPluginContext()).inflate(entry.layoutID(), null);
            setContentView(layout);
        } catch (Exception e) {
            e.printStackTrace();
        }

//
//        try {
////            InputStream in = getAssets().open("layout.xml");
////            try {
////                // 文件长度
////                int len = (in.read() & 0xFF) << 24;
////                len |= (in.read() & 0xFF) << 16;
////                len |= (in.read() & 0xFF) << 8;
////                len |= (in.read() & 0xFF);
////
////                // 读取文件内容
////                buffer = new byte[len];
////                in.read(buffer);
////            } finally {
////                in.close();
////            }
//            byte[] buffer = readStream(getAssets().open("layout.xml"));
//
//
//            Class clazz = Class.forName("android.content.res.XmlBlock");
//            Constructor constructor = clazz.getDeclaredConstructor(byte[].class);
//            constructor.setAccessible(true);
//            Object xmlBlock = constructor.newInstance(buffer);
//
//            Method method = clazz.getDeclaredMethod("newParser");
//            method.setAccessible(true);
//
//            XmlPullParser parser = (XmlResourceParser) method.invoke(xmlBlock);//Xml.newPullParser();
////            Reader reader = new InputStreamReader(getAssets().open("layout.xml"));
////            parser.setInput(reader);
//            View view = LayoutInflater.from(this).inflate(parser, null);
//            setContentView(view);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        setContentView(root);
    }

    /**
     * 得到图片字节流 数组大小
     */
    public static byte[] readStream(InputStream inStream) throws Exception {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = -1;
        while ((len = inStream.read(buffer)) != -1) {
            outStream.write(buffer, 0, len);
        }
        outStream.close();
        inStream.close();
        return outStream.toByteArray();
    }


    @Override
    protected void onResume() {
        super.onResume();
//        glSurfaceView.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
//        glSurfaceView.onPause();
    }

    private File copy() {
        try {
            File file = new File(getCacheDir(), "gl.js");
            InputStream is = getAssets().open("gl.js");
            FileOutputStream fos = new FileOutputStream(file);
            byte[] buffer = new byte[1024];
            int byteCount = 0;
            while ((byteCount = is.read(buffer)) != -1) {// 循环从输入流读取
                // buffer字节
                fos.write(buffer, 0, byteCount);// 将读取的输入流写入到输出流
            }
            fos.flush();// 刷新缓冲区
            is.close();
            fos.close();
            return file;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private int loadShader(int i, String s) {
        int fragShader = GLES20.glCreateShader(i);
        GLES20.glShaderSource(fragShader, s);
        GLES20.glCompileShader(fragShader);
        return fragShader;
    }

    private void runNative2() {
        String VSHADER_SOURCE =
                "void main() {" +
                        //设置坐标
                        "gl_Position = vec4(0.0, 0.0, 0.0, 1.0); " +
                        //设置尺寸
                        "gl_PointSize = 10.0; " +
                        "} ";

        //片元着色器
        String FSHADER_SOURCE =
                "void main() {" +
                        //设置颜色
                        "gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);" +
                        "}";
        //获取canvas元素
//    var canvas = document.getElementById('canvas');
//    //获取绘制二维上下文
//    var gl = canvas.getContext('webgl');
//    if (!gl) {
//        console.log("Failed");
//        return;
//    }
        //编译着色器
        int vertShader = loadShader(GLES20.GL_VERTEX_SHADER, VSHADER_SOURCE);

        int fragShader = loadShader(GLES20.GL_FRAGMENT_SHADER, FSHADER_SOURCE);
        //合并程序
        int shaderProgram = GLES20.glCreateProgram();
        GLES20.glAttachShader(shaderProgram, vertShader);
        GLES20.glAttachShader(shaderProgram, fragShader);
        GLES20.glLinkProgram(shaderProgram);
        GLES20.glUseProgram(shaderProgram);

        //绘制一个点
        GLES20.glDrawArrays(GLES20.GL_POINTS, 0, 1);
    }

    private void runNative() {
        GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1);
        int mProgram;
        FloatBuffer vertexBuffer;

        final String vertexShaderCode =
                "attribute vec4 vPosition;" +
                        "void main() {" +
                        "  gl_Position = vPosition;" +
                        "}";

        final String fragmentShaderCode =
                "precision mediump float;" +
                        "uniform vec4 vColor;" +
                        "void main() {" +
                        "  gl_FragColor = vColor;" +
                        "}";

        float triangleCoords[] = {
                0.5f, 0.5f, 0.0f, // top
                -0.5f, -0.5f, 0.0f, // bottom left
                0.5f, -0.5f, 0.0f  // bottom right
        };

        //设置颜色，依次为红绿蓝和透明通道
        float color[] = {1.0f, 0f, 0f, 1.0f};
        final int COORDS_PER_VERTEX = 3;

        int mPositionHandle;
        int mColorHandle;

        //顶点个数
        final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
        //顶点之间的偏移量
        final int vertexStride = COORDS_PER_VERTEX * 4; // 每个顶点四个字节

        ByteBuffer bb = ByteBuffer.allocateDirect(triangleCoords.length * 4);
        bb.order(ByteOrder.nativeOrder());
        //将坐标数据转换为FloatBuffer，用以传入OpenGL ES程序
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(triangleCoords);
        vertexBuffer.position(0);

        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

        //创建一个空的OpenGLES程序
        mProgram = GLES20.glCreateProgram();
        //将顶点着色器加入到程序
        GLES20.glAttachShader(mProgram, vertexShader);
        //将片元着色器加入到程序中
        GLES20.glAttachShader(mProgram, fragmentShader);
        //连接到着色器程序
        GLES20.glLinkProgram(mProgram);

        GLES20.glUseProgram(mProgram);

        //获取顶点着色器的vPosition成员句柄
        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
        //启用三角形顶点的句柄
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        //准备三角形的坐标数据
        GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
                GLES20.GL_FLOAT, false,
                vertexStride, vertexBuffer);
        //获取片元着色器的vColor成员的句柄
        mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
        //设置绘制三角形的颜色
        GLES20.glUniform4fv(mColorHandle, 1, color, 0);
        //绘制三角形
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
        //禁止顶点数组的句柄
        GLES20.glDisableVertexAttribArray(mPositionHandle);

    }

    private void runJS(InputStream inputStream) {
        Class[] clazzs = new Class[]{
                JSObjectGL20.class,
                JSOAndroid.class
        };
        Context cx = ContextFactory.getGlobal().enterContext();
        Scriptable scope = cx.initStandardObjects(null);
        cx.setOptimizationLevel(-1);
        cx.setLanguageVersion(Context.VERSION_1_8);

        for (Class clazz : clazzs)
            try {
                ScriptableObject.defineClass(scope, clazz);
            } catch (Exception e) {
                e.printStackTrace();
            }
        JSObjectGL20 gl = (JSObjectGL20) cx.newObject(scope, "gl");
        scope.put("gl", scope, gl);


        JSOAndroid android = (JSOAndroid) cx.newObject(scope, "android");
        scope.put("android", scope, android);

        try {
//            FileReader fileReader = new FileReader(copy());
            InputStreamReader reader = new InputStreamReader(inputStream);
            long ss = System.currentTimeMillis();
            cx.evaluateReader(scope, reader, "gl.js", 1, null);

            Object fObj = scope.get("js_obj", scope);
            Log.d("JS-CORE", "evaluateReader cost " + (System.currentTimeMillis() - ss));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
